package vn.vfriends.mcms.site.ws;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import vn.vfriends.mcms.site.model.Site;
import vn.vfriends.mcms.site.service.FTPFileService;
import vn.vfriends.mcms.site.service.SiteService;
import vn.vfriends.mcms.site.util.Constants;
import vn.vfriends.mcms.site.ws.exception.WSException;

/**
 *
 * @author tuan@vfirends.vn
 */
@WebService(serviceName = "SiteWS")
public class SiteWS {

    private static final Logger logger = LoggerFactory.getLogger(SiteWS.class);
    
    @Resource private WebServiceContext wsContext;
    
    @Inject private SiteService siteService;
    
    @Inject private FTPFileService ftpFileService;
    
    private static String LOCAL_PATH;
    
    private boolean authenticate() {
        MessageContext messageContext = wsContext.getMessageContext();
        Map headers = (Map) messageContext.get(MessageContext.HTTP_REQUEST_HEADERS);
        List userList = (List) headers.get(Constants.WS_USERNAME);
        List passList = (List) headers.get(Constants.WS_USERNAME);

        String username = (userList != null) ? userList.get(0).toString() : "";
        String password = (passList != null) ? passList.get(0).toString() : "";

        if ("wsuser".equals(username) && "wsuser".equals(password)) {
            return true;
        } else {
            return false;
        }
    }
    
    @WebMethod(operationName = "deploySite")
    public void deploySite(@WebParam(name = "siteName") String siteName) throws WSException {
        try {
            boolean isAuthenticated = this.authenticate();
            if (!isAuthenticated) {
                logger.info("Authentication failed");
                throw new WSException(WSException.AUTHENTICATION_FAILED, "Authentication failed");
            } else {
                if(StringUtils.isEmpty(LOCAL_PATH)) {
                    ServletContext servletContext = (ServletContext)wsContext.getMessageContext().get(MessageContext.SERVLET_CONTEXT);
                    LOCAL_PATH = servletContext.getInitParameter("LOCAL_PATH");
                }
                Site site = this.siteService.findSiteByName(siteName);
                String localPath = FilenameUtils.concat(LOCAL_PATH, site.getName());
                File siteFile = new File(localPath);
                if(siteFile.exists()) {
                    FileUtils.deleteDirectory(siteFile);
                }
                // Write site
                try {
                    FileUtils.forceMkdir(siteFile);
                    writeLocalSite(File.separator + site.getName());
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    throw new ServletException(e);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new WSException(WSException.ERROR, e.getMessage());
        }
    }
    
    private void writeLocalSite(String path) throws Exception {
        FTPFile[] ftpFiles = this.ftpFileService.listFiles(path);
        for (FTPFile ftpFile : ftpFiles) {
            this.writeFile(ftpFile, path);
        }
    }
    
    private void writeFile(FTPFile ftpFile, String path) throws Exception {
        File file = new File(FilenameUtils.concat(LOCAL_PATH + path, ftpFile.getName()));
        if (ftpFile.isFile()) {
            if (!file.exists()) {
                file.createNewFile();
            }
            OutputStream outStream = null;
            try {
                outStream = new FileOutputStream(file);
                this.ftpFileService.retrieveFile(FilenameUtils.concat(path, ftpFile.getName()), outStream);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                throw e;
            } finally {
                IOUtils.closeQuietly(outStream);
            }
        } else {
            FileUtils.forceMkdir(file);
            FTPFile[] ftpFiles = this.ftpFileService.listFiles(FilenameUtils.concat(path, file.getName()));
            for (FTPFile childFile : ftpFiles) {
                this.writeFile(childFile, FilenameUtils.concat(path, file.getName()));
            }
        }
    }
}
